#include "tan_list.h"
#include "tan_error.h"

typedef struct TanListNode
{
	struct TanListNode* prevNode;
	struct TanListNode* nextNode;
	void* data;
} TanListNode;

TanList* tan_list_create()
{
	TanList* _list = (TanList*)malloc(sizeof(TanList));
	if (_list) memset(_list, 0, sizeof(TanList));
	return _list;
}

void tan_list_free(TanList* list)
{
	if (list)
	{
		while (list->size != 0)  tan_list_pop_front(list);
		free(list);
	}
}

void tan_list_push_front(TanList* list, TAN_POINTER data)
{
	TanListNode* node = (TanListNode*)malloc(sizeof(TanListNode));
	if (node)
	{
		memset(node, 0, sizeof(TanListNode));
		node->data = data;
		node->nextNode = list->firstNode;
		if (list->firstNode != 0)
		{
			list->firstNode->prevNode = node;
		}
		if (list->size == 0)
		{
			list->lastNode = node;
		}
		list->firstNode = node;
		list->size++;
	}
	else tan_assert(0, "list failed to apply for memory space.");
}

void tan_list_push_back(TanList* list, TAN_POINTER data)
{
	TanListNode* node = (TanListNode*)malloc(sizeof(TanListNode));
	if (node)
	{
		memset(node, 0, sizeof(TanListNode));
		node->data = data;
		node->prevNode = list->lastNode;
		if (list->lastNode != 0)
		{
			list->lastNode->nextNode = node;
		}
		if (list->size == 0)
		{
			list->firstNode = node;
		}
		list->lastNode = node;
		list->size++;
	}
	else tan_assert(0, "list failed to apply for memory space.");
}

void tan_list_pop_front(TanList* list)
{
	if (list->firstNode == 0) return;

	if (list->firstNode->nextNode != 0)
	{
		list->firstNode = list->firstNode->nextNode;
		free(list->firstNode->prevNode);
		list->firstNode->prevNode = 0;
	}
	else
	{
		free(list->firstNode);
		list->firstNode = 0;
	}

	list->size--;

	if (list->size == 0) list->lastNode = 0;
}

void tan_list_pop_back(TanList* list)
{
	if (list->lastNode == 0) return;

	if (list->lastNode->prevNode != 0)
	{
		list->lastNode = list->lastNode->prevNode;
		free(list->lastNode->nextNode);
		list->lastNode->nextNode = 0;
	}
	else
	{
		free(list->lastNode);
		list->lastNode = 0;
	}

	list->size--;
	if (list->size == 0) list->firstNode = 0;
}

void tan_list_remove(TanList* list, TAN_INT32 pos)
{
	if (pos < 0) return;

	TanListNode* curNode = list->firstNode;
	TanListNode* prevNode = 0;
	TanListNode* nextNode = 0;

	for (TAN_INT32 i = 0; i < pos; i++)
	{
		if (curNode->nextNode != 0) curNode = curNode->nextNode;
		else { curNode = 0; break; }
	}

	if (curNode == 0)  return 0;

	if (curNode != list->firstNode) {
		curNode->prevNode->nextNode = curNode->nextNode;
		if (curNode->nextNode)
			curNode->nextNode->prevNode = curNode->prevNode;
	}
	else {
		list->firstNode = curNode->nextNode;
		if(curNode->nextNode)
			curNode->nextNode->prevNode = 0;
	}

	free(curNode);
	
	list->size--;
}

void* tan_list_at(TanList* list, TAN_INT32 pos)
{
	if (pos < 0 && pos >= list->size) return 0;

	TanListNode* curNode = list->firstNode;

	for (TAN_INT32 i = 0; i < pos; i++)
	{
		if (curNode->nextNode != 0) curNode = curNode->nextNode;
		else { curNode = 0; break; }
	}

	if (curNode == 0)  return 0;
	return curNode->data;
}
